using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace net.bistre.pfwl {

	/// <summary>
	/// Core code that handles the two Net and one IO Stream.
	/// </summary>
	public class PfwlCore {
		private Socket socketIn=null;
		private IPAddress ipaIP=null;
		private int iPort;
		private TextWriter streamLog;

		/// <summary>
		/// PfwlCore Constructor
		/// </summary>
		/// <param name="client">Local binding socket (IP and Port).</param>
		/// <param name="ipaIpOut">Target IP Address.</param>
		/// <param name="iPortOut">Target IP Port.</param>
		/// <param name="filestreamLog">Log file FileStream.</param>
		public PfwlCore(Socket client, IPAddress ipaIpOut, int iPortOut, TextWriter filestreamLog) {
			socketIn = client;
			ipaIP = ipaIpOut;
			iPort = iPortOut;
			streamLog = filestreamLog;
		}

		/// <summary>
		/// Main method, launched onto  it's own thread by the main code.
		/// </summary>
		public void ThreadProc() {
			const string CR  = "\u000d"; /*13 = CR*/
			const string LF  = "\u000a"; /*10 = LF*/
			const string TAB = "\u0009"; /*9*/

			/* 1MB buffer, this is fairly big and useally apps would sent something
			a LOT smaller */
			const int BUFFER_SIZE = 11048576;
		
		
			byte[] logBuffer;
			Byte[] buffer;

			Socket socketOut;

			Console.WriteLine("Thread started");
		
			// Buffer for reading data
			buffer = new Byte[BUFFER_SIZE];
		

			// Start Outwards connection
			IPEndPoint ipepOut = new IPEndPoint(ipaIP, iPort);
			socketOut = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
			socketOut.Connect(ipepOut);
		
		
			bool bStateIn= true;
			bool bStateOut= true;
			int i;
			while (bStateIn && bStateOut) {
				if (socketIn.Available > 0) {
					//Get data from incomming socket
					i = socketIn.Receive(buffer);
				
					//Write to outgoing socket
					socketOut.Send(buffer,i,SocketFlags.None);
				
					//Log to file
					if (streamLog != null) {
						streamLog.Write(String.Format(" In -> Out:{0}\n", System.Text.Encoding.ASCII.GetString(buffer, 0, i)));
						streamLog.Flush();
						logBuffer=null;
					}
				}

				/* This piece of code is about the only way to detect a closed 
						connection. Thanks MS........  */
				if (socketIn.Poll(1, SelectMode.SelectRead) && (socketIn.Available == 0))
					bStateIn = false;

				if (socketOut.Available > 0) {
					//Get data from outgoing socket
					i = socketOut.Receive(buffer);
				
					//Write to incomming socket
					socketIn.Send(buffer,i,SocketFlags.None);
				
					//Log to File
					if (streamLog != null) {
						streamLog.Write(String.Format("Out -> In :{0}\n", System.Text.Encoding.ASCII.GetString(buffer, 0, i)));
						streamLog.Flush();
						logBuffer=null;
					}
				}
				/* This piece of code is about the only way to detect a closed 
						connection. Thanks MS........  */
				if (socketOut.Poll(1, SelectMode.SelectRead) && (socketOut.Available == 0))
					bStateOut = false;

			}
		
			if (socketIn != null) socketIn.Close();
			if (socketOut != null) socketOut.Close();
			Console.WriteLine("Closing Conection and Thread");

		}
	}
}